package xyz.vsl.mybatis.generator.pluginsplus;

import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.Plugin;
import org.mybatis.generator.api.dom.java.*;
import org.mybatis.generator.api.dom.java.Field;
import org.mybatis.generator.api.dom.java.Method;
import org.mybatis.generator.api.dom.xml.Attribute;
import org.mybatis.generator.api.dom.xml.Element;
import org.mybatis.generator.api.dom.xml.TextElement;
import org.mybatis.generator.api.dom.xml.XmlElement;
import org.mybatis.generator.internal.rules.Rules;

import java.util.ListIterator;
import java.util.Map;
import java.util.Stack;
import java.util.regex.Pattern;

import static org.mybatis.generator.api.dom.java.JavaVisibility.PRIVATE;
import static org.mybatis.generator.api.dom.java.JavaVisibility.PUBLIC;

/**
 * MyBatis Generator utilities
 *
 * @author Vladimir Lokhov
 */
final class MBGenerator {

    public static class FQJT {
        public final static FullyQualifiedJavaType LIST_OF_STRING = new FullyQualifiedJavaType("java.util.List<java.lang.String>");
        public final static FullyQualifiedJavaType LIST_OF_INTEGER = new FullyQualifiedJavaType("java.util.List<java.lang.Integer>");
        public final static FullyQualifiedJavaType LIST_OF_LONG = new FullyQualifiedJavaType("java.util.List<java.lang.Long>");
        public final static FullyQualifiedJavaType STRING = FullyQualifiedJavaType.getStringInstance();
        public final static FullyQualifiedJavaType BOOL = FullyQualifiedJavaType.getBooleanPrimitiveInstance();
        public final static FullyQualifiedJavaType BOOLEAN = new FullyQualifiedJavaType("java.lang.Boolean");
        public final static FullyQualifiedJavaType OBJECT = FullyQualifiedJavaType.getObjectInstance();
        public final static FullyQualifiedJavaType CRITERIA = FullyQualifiedJavaType.getCriteriaInstance();
        public final static FullyQualifiedJavaType INT = FullyQualifiedJavaType.getIntInstance();
        public final static FullyQualifiedJavaType INTEGER = PrimitiveTypeWrapper.getIntegerInstance();
        public final static FullyQualifiedJavaType VOID = null;

        public final static FQJT STATIC = new FQJT();
        public final static FQJT FINAL = new FQJT();
        public final static FQJT SYNCHRONIZED = new FQJT();
        public final static FQJT VOLATILE = new FQJT();
        public final static FQJT TRANSIENT = new FQJT();

        private FQJT() {
        }
    }

    public static String camel(String name) {
        return Character.toUpperCase(name.charAt(0)) + (name.length() > 1 ? name.substring(1) : "");
    }

    public static JavaMethod method(Object... args) {
        JavaMethod m = new JavaMethod();
        for (Object o : args) {
            if (o == null) continue;

            if (o instanceof JavaVisibility) m.setVisibility((JavaVisibility) o);
            else if (o instanceof FullyQualifiedJavaType) m.setReturnType((FullyQualifiedJavaType) o);
            else if (o instanceof Parameter) m.addParameter((Parameter) o);
            else if (o instanceof String) m.setName((String) o);
            else if (o instanceof StringBuilder) m.addBodyLine(((StringBuilder) o).toString().replace('`', '"'));
            else if (o instanceof String[]) {
                for (String s : (String[]) o) if (s != null) m.addBodyLine(s.replace('`', '"'));
            } else if (o instanceof Parameter[]) {
                for (Parameter p : (Parameter[]) o) if (p != null) m.addParameter(p);
            } else if (o instanceof Throwable) m.addException(new FullyQualifiedJavaType(o.getClass().getName()));
            else if ((o instanceof Class<?>) && Throwable.class.isAssignableFrom((Class<?>) o))
                m.addException(new FullyQualifiedJavaType(((Class<?>) o).getName()));
            else if (o == FQJT.STATIC) m.setStatic(true);
            else if (o == FQJT.FINAL) m.setFinal(true);
            else if (o == FQJT.SYNCHRONIZED) m.setSynchronized(true);
        }
        return m;
    }

    public static StringBuilder _(String s, String... args) {
        if (args.length == 0)
            return new StringBuilder(s);
        return new StringBuilder(String.format(s, (Object[]) args));
    }

    public static Parameter _(FullyQualifiedJavaType type, String name) {
        return new Parameter(type, name);
    }

    public static Parameter _(FullyQualifiedJavaType type, String name, boolean isVararg) {
        return new Parameter(type, name, isVararg);
    }

    public static String[] __(CharSequence... args) {
        String[] lines = new String[args.length];
        for (int i = 0; i < args.length; i++)
            if (args[i] != null) lines[i] = args[i].toString();
        return lines;
    }

    public static Parameter[] __(Parameter... args) {
        return args;
    }

    public static Parameter[] __(Method method) {
        if (method == null || method.getParameters() == null)
            return new Parameter[0];
        return method.getParameters().toArray(new Parameter[method.getParameters().size()]);
    }
}